package org.example.lotterysystem.service.impl;

import org.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import org.example.lotterysystem.common.exception.ServiceException;
import org.example.lotterysystem.common.utils.JacksonUtil;
import org.example.lotterysystem.common.utils.RedisUtil;
import org.example.lotterysystem.controller.param.DrawPrizeParam;
import org.example.lotterysystem.dao.dataobject.*;
import org.example.lotterysystem.dao.mapper.*;
import org.example.lotterysystem.service.DrawPrizeService;
import org.example.lotterysystem.service.enmus.ActivityPrizeStatusEnum;
import org.example.lotterysystem.service.enmus.ActivityStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static org.example.lotterysystem.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static org.example.lotterysystem.common.config.DirectRabbitConfig.ROUTING;

@Service
public class DrawPrizeServiceImpl implements DrawPrizeService {
    private static final Logger logger = LoggerFactory.getLogger(DrawPrizeServiceImpl.class);
    private final Long WINNING_RECORDS_TIMEOUT = 60 * 60 * 24 * 2L;
    private final String WINNING_RECORDS_PREFIX = "WINNING_RECORDS_";
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private ActivityUserMapper activityUserMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PrizeMapper prizeMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public void drawPrize(DrawPrizeParam param) {

        Map<String,String> map = new HashMap<>();
        map.put("messageId",String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeValueAsString(param));
        //发消息，交换机，key，消息体。
        rabbitTemplate.convertAndSend(EXCHANGE_NAME,ROUTING,map);
        logger.info("mq消息发送成功：map={}", JacksonUtil.writeValueAsString(map));
    }

    @Override
    public Boolean checkDrawPrizeParam(DrawPrizeParam param) {

        //这里要明白这一点，抽奖是前端做的，他只是将中间名单和中的奖品数据传给后端，也就是从消息队列中拿东西进行保存，和同步redis
        ActivityDO activityDO = activityMapper.selectById(param.getActivityId());
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByPrizeIdAndActivityId(param.getActivityId(), param.getPrizeId());

        //校验活动或者奖品是否存在
        if(activityDO==null||activityPrizeDO==null){
            logger.info("校验抽奖请求失败！失败原因：{}",ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY);
            return false;
        }
        //校验活动是否有效
        if(activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.ACTIVITY_COMPLETED.getMsg());
            return false;
        }

        //校验奖品是否有效
        if(activityPrizeDO.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETED.name())){
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED.getMsg());
            return false;
        }
        //中奖者人数是否与奖品数量一致
        if(param.getWinnerList().size()==activityPrizeDO.getPrizeAmount()){
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR.getMsg());
            return false;
        }
        return true;

    }

    @Override
    public List<WinningRecordDO> saveWinnerRecords(DrawPrizeParam param) {
        //要存数据的话，还是先从数据库中查询数据
        //活动表
        ActivityDO activityDO = activityMapper.selectById(param.getActivityId());
        //活动奖品关联表
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());
        //人员表
        List<UserDO>userDOList= userMapper.bathSelectByIds(param.getWinnerList().stream().map(DrawPrizeParam.Winner::getUserId).collect(Collectors.toList()));
        //奖品表
        PrizeDO prizeDO=prizeMapper.selectById(param.getPrizeId());
        //构造中奖者记录，保存，存到中奖记录表中
        List<WinningRecordDO> winningRecordDOList=userDOList.stream().map(userDO -> {
            WinningRecordDO winningRecordDO=new WinningRecordDO();
            winningRecordDO.setActivityId(activityDO.getId());
            winningRecordDO.setActivityName(activityDO.getActivityName());
            winningRecordDO.setPrizeId(prizeDO.getId());
            winningRecordDO.setPrizeName(prizeDO.getName());
            winningRecordDO.setPrizeTier(activityPrizeDO.getPrizeTiers());
            winningRecordDO.setWinnerId(userDO.getId());
            winningRecordDO.setWinnerName(userDO.getUserName());
            winningRecordDO.setWinnerEmail(userDO.getEmail());
            winningRecordDO.setWinningTime(param.getWinningTime());
            return winningRecordDO;
        }).collect(Collectors.toList());

        //写入数据库
        winningRecordMapper.batchInsert(winningRecordDOList);

        //将中奖者记录存到redis中
        cacheWinningRecords(param.getActivityId()+"_"+param.getPrizeId(),winningRecordDOList,WINNING_RECORDS_TIMEOUT);

        //缓存活动维度中奖记录（WinningRecord_activityId,winningRecordDOList(活动维度的中奖者名单）
        if(activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            //查询活动维度权力中奖记录
            List<WinningRecordDO> allList=winningRecordMapper.selectByActivityId(param.getActivityId());
            cacheWinningRecords(String.valueOf(param.getActivityId()),allList,WINNING_RECORDS_TIMEOUT);
        }
        return winningRecordDOList;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if(null==activityId){
            logger.warn("要删除的中奖记录相关的活动id为空");
            return;

        }
        //删除数据
        winningRecordMapper.deleteRecords(activityId,prizeId);
        if(null==prizeId){
            deleteWinnerRecords(activityId+"_"+prizeId);
        }
        deleteWinnerRecords(String.valueOf(activityId));
    }
    //删除缓存中的数据
    private void deleteWinnerRecords(String key) {
        try{
            if(redisUtil.hasKey(WINNING_RECORDS_PREFIX+key)){
                redisUtil.delete(WINNING_RECORDS_PREFIX+key);
            }
        }catch (Exception e){
            logger.error("删除中奖记录缓存异常，key：{}",key);
        }
    }

    /**
     * 将中奖者记录存到redis中
     * @param key
     * @param winningRecordDOList
     * @param time
     */
    private void cacheWinningRecords(String key, List<WinningRecordDO> winningRecordDOList, Long time) {
        String str="";
        try{
            if(!StringUtils.hasText(key)|| CollectionUtils.isEmpty(winningRecordDOList)){
                logger.warn("要缓存的内容为空！key：{}，value：{}",key,JacksonUtil.writeValueAsString(winningRecordDOList));
                return;
            }
            str=JacksonUtil.writeValueAsString(winningRecordDOList);
            redisUtil.set(WINNING_RECORDS_TIMEOUT+key,str,time);
        }catch (Exception e){
            logger.error("缓存中奖记录一场！key：{}，value：{}",WINNING_RECORDS_TIMEOUT+key,str);
        }
    }
}
